<?php
namespace Tbf\Bundle\TbfBundle\Error;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Tbf\Component\Debug\Debug;
use Tbf\Component\Debug\Stack\StackFunction;

/**
 * 不管别处怎么搞,此处尝试log下所有error!!!
 */
class ErrorsLoggerListener implements EventSubscriberInterface
{
    static private $enable=false;
    private $logger;
    private $debug;
    private $reservedMemory;
    private $previous_error_handle;
    private $levels = array(
        E_WARNING           => 'Warning',
        E_NOTICE            => 'Notice',
        E_USER_ERROR        => 'User Error',
        E_USER_WARNING      => 'User Warning',
        E_USER_NOTICE       => 'User Notice',
        E_STRICT            => 'Runtime Notice',
        E_RECOVERABLE_ERROR => 'Catchable Fatal Error',
        E_DEPRECATED        => 'Deprecated',
        E_USER_DEPRECATED   => 'User Deprecated',
        E_ERROR             => 'Error',
        E_CORE_ERROR        => 'Core Error',
        E_COMPILE_ERROR     => 'Compile Error',
        E_PARSE             => 'Parse',
    );
    public function __construct(LoggerInterface $logger = null,$debug=false)
    {
        $this->logger = $logger;
        $this->debug = $debug;
    }

    public function injectLogger()
    {
        if (self::$enable){
            return ;
        }
        self::$enable = true;
        if ($this->debug){
            ini_set('display_errors', 1);
        }else{
            ini_set('display_errors', 0);
        }
        $this->previous_error_handle = set_error_handler(array($this, 'handle'));
        register_shutdown_function(array($this, 'handleFatal'));
        $this->reservedMemory = str_repeat('x', 10240);
    }

    public function handle($level, $message, $file = 'unknown', $line = 0, $context = array())
    {
        if (isset($this->levels[$level])){
            $level = $this->levels[$level];
        }
        $this->logger->error('TbfBundle\Error handle',array(
            'level'=>$level,
            'message'=>$message,
            'file'=>$file,
            'line'=>$line,
            'trace'=>StackFunction::stackHereArray(1),
        ));
        if ($this->previous_error_handle){
            call_user_func($this->previous_error_handle,$level,$message,$file,$line,$context);
        }
        return false;
    }
    public function handleFatal()
    {
        if (null === $error = error_get_last()) {
            return;
        }

        unset($this->reservedMemory);
        $type = $error['type'];
        if (!in_array($type, array(E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE))) {
            return;
        }

        $this->logger->error('TbfBundle\Error fatal',array(
            'message'=>$error['message'],
            'type'=>$type,
            'file'=>$error['file'],
            'line'=>$error['line'],
            'trace'=>StackFunction::stackHereArray(2),
        ));
    }
    public static function getSubscribedEvents()
    {
        return array(KernelEvents::REQUEST => 'injectLogger');
    }
}
